
from saas.func import *
import struct



##################################################################################################################################
##
##  PING
##
def handle_ping( inst , payload ):
	## echo back the payload that they sent to us.
	return payload





##################################################################################################################################
##
##  AUTH
##
def handle_authenticate( inst , payload ):
	## extract the length of the username (must be less than 256)
	username_len = struct.unpack( '> B' , payload[0] )[0]
	offset       = 1

	## extract the username itself
	username     = payload[offset:offset+username_len]
	offset      += username_len

	## extract the sha512 password hash
	pwhash       = payload[offset:offset+64]
	offset      += 64

	## we now have everything we need to make the auth request.
	## pass the auth request to the functionality layer, which will do the actual checks.
	( result , pw_expiry ) = func_authenticate( inst , username , pwhash )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully authenticated user `%s\'' % ( username ) )
	else:
		logm( LOG_DEBUG , 'failed authenticating user `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )

	return struct.pack( '> H H I' , result , 0 , pw_expiry );





##################################################################################################################################
##
##  CHANGE PASSWORD
##
def handle_change_password( inst , payload ):
	pass





##################################################################################################################################
##
##  UID to USERNAME
##
def handle_uid_to_username( inst , payload ):
	## extract the UID from the payload.
	uid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	( result , username ) = func_uid_to_username( inst , uid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved UID %d to username `%s\'' % ( uid , username ) )
	else:
		logm( LOG_DEBUG , 'failed resolving UID %d: (%d) %s' % ( uid , result , saaserror( result ) ) )

	## pack the 16-bit result, and a reserved 16-bit field, and the
	## length of the username.
	payload = struct.pack( '> H H B' , result , 0 , len( username ) )

	## tack on the username itself...
	payload += username.encode( 'ascii' )

	return payload




##################################################################################################################################
##
##  USERNAME to UID
##
def handle_username_to_uid( inst , payload ):
	## extract the length of the username
	username_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the username itself
	username     = payload[1:1+username_len]

	## go and perform the lookup via the functionality layer.
	( result , uid ) = func_username_to_uid( inst , username )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved username `%s\' to UID %d' % ( username , uid ) )
	else:
		logm( LOG_DEBUG , 'failed resolving username `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )

	## pack the 16-bit result, and a reserved 16-bit field, and the
	## 32-bit UID.
	return struct.pack( '> H H I' , result , 0 , uid )




##################################################################################################################################
##
##  GID to GROUPNAME
##
def handle_gid_to_groupname( inst , payload ):
	## extract the GID from the payload.
	gid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	( result , groupname ) = func_gid_to_groupname( inst , gid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved GID %d to groupname `%s\'' % ( gid , groupname ) )
	else:
		logm( LOG_DEBUG , 'failed resolving GID %d: (%d) %s' % ( gid , result , saaserror( result ) ) )

	## pack the 16-bit result, and a reserved 16-bit field, and the
	## length of the groupname.
	payload = struct.pack( '> H H B' , result , 0 , len( groupname ) )

	## tack on the groupname itself...
	payload += groupname.encode( 'ascii' )

	return payload




##################################################################################################################################
##
##  GROUPNAME to GID
##
def handle_groupname_to_gid( inst , payload ):
	## extract the length of the groupname
	groupname_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	groupname     = payload[1:1+groupname_len]

	## go and perform the lookup via the functionality layer.
	( result , gid ) = func_groupname_to_gid( inst , groupname )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG	, 'successfully resolved groupname `%s\' to GID %d' % ( groupname , gid ) )
	else:
		logm( LOG_DEBUG , 'failed resolving groupname `%s\': (%d) %s' % ( groupname , result , saaserror( result ) ) )

	## pack the 16-bit result, and a reserved 16-bit field, and the
	## 32-bit GID.
	return struct.pack( '> H H I' , result , 0 , gid )




##################################################################################################################################
##
##  USER INFO
##
def _pack_user_info( inst , user_info ):
	## pack the UID and GIDs first
	payload = struct.pack( '> I I' , user_info['uid'] , user_info['gid'] )

	## pack the username
	payload += struct.pack( '> B' , len( user_info['username'] ) )
	payload += user_info['username'].encode( 'ascii' )

	## pack the fullname
	payload += struct.pack( '> B' , len( user_info['fullname'] ) )
	payload += user_info['fullname'].encode( 'ascii' )

	## pack the displayname
	payload += struct.pack( '> B' , len( user_info['displayname'] ) )
	payload += user_info['displayname'].encode( 'ascii' )

	## pack the fname, lname and email
	payload += struct.pack( '> B' , len( user_info['fname'] ) )
	payload += user_info['fname'].encode( 'ascii' )
	payload += struct.pack( '> B' , len( user_info['lname'] ) )
	payload += user_info['lname'].encode( 'ascii' )
	payload += struct.pack( '> B' , len( user_info['email'] ) )
	payload += user_info['email'].encode( 'ascii' )

	## and finally, pack the home_dir and shell.
	payload += struct.pack( '> B' , len( user_info['home_dir'] ) )
	payload += user_info['home_dir'].encode( 'ascii' )
	payload += struct.pack( '> B' , len( user_info['shell'] ) )
	payload += user_info['shell'].encode( 'ascii' )

	return payload



def _pack_user_groups( inst , groups ):
	## groups should have the format [ (gid,groupname), (gid,groupname), etc ]
	payload = ''
	for ( gid , groupname ) in groups:
		payload += struct.pack( '> I' , gid )
		payload += struct.pack( '> B' , len( groupname ) )
		payload += groupname.encode( 'ascii' )
	return payload



def handle_user_info_by_uid( inst , payload ):
	## extract the UID from the payload.
	uid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	( result , user_info ) = func_user_info_by_uid( inst , uid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved user information about UID %d: %s' % ( uid , str( user_info ) ) )
	else:
		logm( LOG_DEBUG , 'failed resolving user information about UID %d: (%d) %s' % ( uid , result , saaserror( result ) ) )

	## throw all the user info into the payload.
	if result == SAAS_OP_SUCCESS:
		payload = _pack_user_info( inst , user_info )
	else:
		payload = ''
	return struct.pack( '> H H' , result , 0 ) + payload



def handle_user_info_by_username( inst , payload ):
	## extract the length of the username
	username_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	username = payload[1:1+username_len]

	## go and perform the lookup via the functionality layer.
	( result , user_info ) = func_user_info_by_username( inst , username )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved user information about username `%s\': %s' % ( username , str( user_info ) ) )
	else:
		logm( LOG_DEBUG , 'failed resolving user information about username `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )

	## throw all the user info into the payload.
	if result == SAAS_OP_SUCCESS:
		payload = _pack_user_info( inst , user_info )
	else:
		payload = ''

	return struct.pack( '> H H' , result , 0 ) + payload



def handle_user_info_with_groups_by_uid( inst , payload ):
	## extract the UID from the payload.
	uid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	groups = []
	( result , user_info ) = func_user_info_by_uid( inst , uid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved user information about UID %d: %s' % ( uid , str( user_info ) ) )
		( result , groups    ) = func_user_groups_by_uid( inst , uid )
		if result == SAAS_OP_SUCCESS:
			logm( LOG_DEBUG , 'successfully resolved group membership information about UID %d: %s' % ( uid , str( groups ) ) )
			## throw all the user info into the payload.
			payload  = _pack_user_info( inst , user_info )
			payload += _pack_user_groups( inst , groups )
		else:
			logm( LOG_DEBUG , 'failed resolving group membership information about UID %d: (%d) %s' % ( uid , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving user information about UID %d: (%d) %s' % ( uid , result , saaserror( result ) ) )
		payload = ''
	return struct.pack( '> H H' , result , len( groups ) ) + payload



def handle_user_info_with_groups_by_username( inst , payload ):
	## extract the length of the username
	username_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	username = payload[1:1+username_len]

	## go and perform the lookup via the functionality layer.
	groups = []
	( result , user_info ) = func_user_info_by_username( inst , username )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved user information about username `%s\': %s' % ( username , str( user_info ) ) )
		( result , groups    ) = func_user_groups_by_username( inst , username )
		if result == SAAS_OP_SUCCESS:
			logm( LOG_DEBUG , 'successfully resolved group membership information about username `%s\': %s' % ( username , str( groups ) ) )
			## throw all the user info into the payload.
			payload  = _pack_user_info( inst , user_info )
			payload += _pack_user_groups( inst , groups )
		else:
			logm( LOG_DEBUG , 'failed resolving group membership information about username `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving user information about username `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )
		payload = ''
	return struct.pack( '> H H' , result , len( groups ) ) + payload



def handle_user_info_with_all_groups_by_uid( inst , payload ):
	## extract the UID from the payload.
	uid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	groups = []
	( result , user_info ) = func_user_info_by_uid( inst , uid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved user information about UID %d: %s' % ( uid , str( user_info ) ) )
		( result , groups    ) = func_user_all_groups_by_uid( inst , uid )
		if result == SAAS_OP_SUCCESS:
			logm( LOG_DEBUG , 'successfully resolved all group membership information about UID %d: %s' % ( uid , str( groups ) ) )
			## throw all the user info into the payload.
			payload  = _pack_user_info( inst , user_info )
			payload += _pack_user_groups( inst , groups )
		else:
			logm( LOG_DEBUG , 'failed resolving all group membership information about UID %d: (%d) %s' % ( uid , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving user information about UID %d: (%d) %s' % ( uid , result , saaserror( result ) ) )
		payload = ''
	return struct.pack( '> H H' , result , len( groups ) ) + payload



def handle_user_info_with_all_groups_by_username( inst , payload ):
	## extract the length of the username
	username_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	username = payload[1:1+username_len]

	## go and perform the lookup via the functionality layer.
	groups = []
	( result , user_info ) = func_user_info_by_username( inst , username )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved user information about username `%s\': %s' % ( username , str( user_info ) ) )
		( result , groups    ) = func_user_all_groups_by_username( inst , username )
		if result == SAAS_OP_SUCCESS:
			logm( LOG_DEBUG , 'successfully resolved all group membership information about username `%s\': %s' % ( username , str( groups ) ) )
			## throw all the user info into the payload.
			payload  = _pack_user_info( inst , user_info )
			payload += _pack_user_groups( inst , groups )
		else:
			logm( LOG_DEBUG , 'failed resolving all group membership information about username `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving user information about username `%s\': (%d) %s' % ( username , result , saaserror( result ) ) )
		payload = ''
	return struct.pack( '> H H' , result , len( groups ) ) + payload






##################################################################################################################################
##
##  GROUP INFO
##
def _pack_group_info( inst , group_info ):
	## pack the GID first
	payload = struct.pack( '> I' , group_info['gid'] )

	## pack the groupname
	payload += struct.pack( '> B' , len( group_info['groupname'] ) )
	payload += group_info['groupname'].encode( 'ascii' )

	return payload


def _pack_group_members( inst , members ):
	## members should have the format [ (type,id,name), (type,id,name), etc ]
	payload = ''
	for ( mtype , mid , mname ) in members:
		payload += struct.pack( '> B' , mtype )
		payload += struct.pack( '> I' , mid )
		payload += struct.pack( '> B' , len( mname ) )
		payload += mname.encode( 'ascii' )
	return payload



def handle_group_info_by_gid( inst , payload ):
	## extract the GID from the payload.
	gid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	( result , group_info ) = func_group_info_by_gid( inst , gid )
	if result == SAAS_OP_SUCCESS:
		## throw all the group info into the payload.
		logm( LOG_DEBUG , 'successfully resolved group information about GID %d: %s' % ( gid , str( group_info ) ) )
		payload = _pack_group_info( inst , group_info )
	else:
		logm( LOG_DEBUG , 'failed resolving group information about GID %d: (%d) %s' % ( gid , result , saaserror( result ) ) )
		payload = ''

	return struct.pack( '> H H' , result , 0 ) + payload



def handle_group_info_by_groupname( inst , payload ):
	## extract the length of the groupname
	groupname_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	groupname = payload[1:1+groupname_len]

	## go and perform the lookup via the functionality layer.
	( result , group_info ) = func_group_info_by_groupname( inst , groupname )
	if result == SAAS_OP_SUCCESS:
		## throw all the group info into the payload.
		logm( LOG_DEBUG , 'successfully resolved group information about groupname `%s\': %s' % ( groupname , str( group_info ) ) )
		payload = _pack_group_info( inst , group_info )
	else:
		logm( LOG_DEBUG , 'failed resolving group information about groupname `%s\': (%d) %s' % ( groupname , result , saaserror( result ) ) )
		payload = ''

	return struct.pack( '> H H' , result , 0 ) + payload



def handle_group_info_with_members_by_gid( inst , payload ):
	## extract the GID from the payload.
	gid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	members = []
	( result , group_info ) = func_group_info_by_gid( inst , gid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved group information about GID %d: %s' % ( gid , str( group_info ) ) )
		( result , members    ) = func_group_members_by_gid( inst , gid )
		if result == SAAS_OP_SUCCESS:
			## throw all the group & member info into the payload.
			logm( LOG_DEBUG , 'successfully resolved group membership information about GID %d: %s' % ( gid , str( members ) ) )
			payload  = _pack_group_info( inst , group_info )
			payload += _pack_group_members( inst , members )
		else:
			logm( LOG_DEBUG , 'failed resolving group membership information about GID %d: (%d) %s' % ( gid , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving group information about GID %d: (%d) %s' % ( gid , result , saaserror( result ) ) )
		payload = ''
	return struct.pack( '> H H' , result , len( members ) ) + payload



def handle_group_info_with_members_by_groupname( inst , payload ):
	## extract the length of the groupname
	groupname_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	groupname = payload[1:1+groupname_len]

	## go and perform the lookup via the functionality layer.
	members = []
	( result , group_info ) = func_group_info_by_groupname( inst , groupname )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved group information about groupname `%s\': %s' % ( groupname , str( group_info ) ) )
		( result , members    ) = func_group_members_by_groupname( inst , groupname )
		if result == SAAS_OP_SUCCESS:
			## throw all the group info into the payload.
			logm( LOG_DEBUG , 'successfully resolved group membership information about groupname `%s\': %s' % ( groupname , str( members ) ) )
			payload  = _pack_group_info( inst , group_info )
			payload += _pack_group_members( inst , members )
		else:
			logm( LOG_DEBUG , 'failed resolving group membership information about groupname `%s\': (%d) %s' % ( groupname , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving group information about groupname `%s\': (%d) %s' % ( groupname , result , saaserror( result ) ) )
		payload = ''

	return struct.pack( '> H H' , result , len( members ) ) + payload



def handle_group_info_with_all_members_by_gid( inst , payload ):
	## extract the GID from the payload.
	gid = struct.unpack( '> I' , payload[0:4] )[0]

	## go and perform the lookup via the functionality layer.
	members = []
	( result , group_info ) = func_group_info_by_gid( inst , gid )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved group information about GID %d: %s' % ( gid , str( group_info ) ) )
		( result , members    ) = func_group_all_members_by_gid( inst , gid )
		if result == SAAS_OP_SUCCESS:
			## throw all the group info into the payload.
			logm( LOG_DEBUG , 'successfully resolved all group membership information about GID %d: %s' % ( gid , str( members ) ) )
			payload  = _pack_group_info( inst , group_info )
			payload += _pack_group_members( inst , members )
		else:
			logm( LOG_DEBUG , 'failed resolving all group membership information about GID %d: (%d) %s' % ( gid , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving group information about GID %d: (%d) %s' % ( gid , result , saaserror( result ) ) )
		payload = ''

	return struct.pack( '> H H' , result , len( members ) ) + payload


def handle_group_info_with_all_members_by_groupname( inst , payload ):
	## extract the length of the groupname
	groupname_len = struct.unpack( '> B' , payload[0] )[0]

	## extract the groupname itself
	groupname = payload[1:1+groupname_len]

	## go and perform the lookup via the functionality layer.
	members = []
	( result , group_info ) = func_group_info_by_groupname( inst , groupname )
	if result == SAAS_OP_SUCCESS:
		logm( LOG_DEBUG , 'successfully resolved group information about groupname `%s\': %s' % ( groupname , str( group_info ) ) )
		( result , members    ) = func_group_all_members_by_groupname( inst , groupname )
		if result == SAAS_OP_SUCCESS:
			## throw all the group info into the payload.
			logm( LOG_DEBUG , 'successfully resolved all group membership information about groupname `%s\': %s' % ( groupname , str( members ) ) )
			payload  = _pack_group_info( inst , group_info )
			payload += _pack_group_members( inst , members )
		else:
			logm( LOG_DEBUG , 'failed resolving all group membership information about groupname `%s\': (%d) %s' % ( groupname , result , saaserror( result ) ) )
			payload = ''
	else:
		logm( LOG_DEBUG , 'failed resolving group information about groupname `%s\': (%d) %s' % ( groupname , result , saaserror( result ) ) )
		payload = ''

	return struct.pack( '> H H' , result , len( members ) ) + payload




